#ifndef MSC_QUEUE_H
#define MSC_QUEUE_H

#include "stack.h"

//c queue
typedef struct ms_stack_item_s ms_queue_item_s;
typedef ms_stack_item_t ms_queue_item_t;
typedef ms_stack_item ms_queue_item;
typedef ms_class_t ms_queue_funs;
//排队:队尾进，队头出
typedef struct ms_queue_s {
    ms_alloc_t* ac;
    ms_queue_item_t* head;  //队头
    ms_queue_item_t* tail;  //队尾
    size_t size;
    size_t count;
    ms_queue_funs fs;
}ms_queue_t, *ms_queue;

CPUBLIC ms_queue ms_queue_create(ms_alloc_t* ac, size_t size, ms_queue_funs* fs) {
    if (!ac) {
        ac = ms_global_alloc();
    }
    ms_queue q = (ms_queue)ms_allocate(ac, sizeof(ms_queue_t));
    if (q) {
        q->ac = ac;
        q->head = NULL;
        q->tail = NULL;
        if (size)
            q->size = size;
        else
            q->size = msc_size_ptr_;
        q->count = 0;
        ms_type_initclass(&q->fs, fs);
    }
    return q;
}

CPUBLIC void ms_queue_clear(ms_queue q) {
    if (q) {
        ms_queue_item i = q->head;
        while (i) {
            ms_queue_item item = i;
            i = i->next;
            q->fs.destroy(item->p);
            ms_deallocate(q->ac, item);
        }
        q->head = NULL;
        q->tail = NULL;
        q->count = 0;
    }
}

CPUBLIC void ms_queue_destory(ms_queue q) {
#ifdef _IF_NULL_
    if (q) {
#endif
    ms_queue_clear(q);
    ms_deallocate(q->ac, q);
#ifdef _IF_NULL_
    }
#endif
}

CPUBLIC bool ms_queue_empty(ms_queue q) {
    return (NULL == q) || (NULL == q->head);
}

CPUBLIC size_t ms_queue_size(ms_queue q) {
#ifdef _IF_NULL_
    if (q) {
#endif
    return q->count;
#ifdef _IF_NULL_
    }
    return 0;
#endif
}

CPUBLIC bool ms_queue_push_back(ms_queue q, void* data) {
#ifdef _IF_NULL_
    if (q) {
#endif
    ms_queue_item item = (ms_queue_item)ms_allocate(q->ac, sizeof(ms_queue_item_t)+q->size);
    if (item) {
        q->fs.construct(item->p);
        q->fs.copy(item->p, data);
        item->next = NULL; //队尾没有
        if (q->tail) {
            q->tail->next = item;
        }
        else {//queue empty
            q->head = item;
        }
        q->tail = item; //重置队尾
        ++q->count;
        return true;
    }
#ifdef _IF_NULL_
    }
#endif
    return false;
}
#define ms_quequ_push   ms_queue_push_back

CPUBLIC void ms_queue_pop_front(ms_queue q) {
#ifdef _IF_NULL_
    if (q) {
#endif
    ms_queue_item_t* item = q->head;
    if (item) {
        q->head = item->next; //重置队头
        ms_deallocate(q->ac, item);
        --q->count;
    }
#ifdef _IF_NULL_
    }
#endif
}
#define ms_queue_pop    ms_queue_pop_front
CPUBLIC void* ms_queue_front(ms_queue q) {
#ifdef _IF_NULL_
    if (!ms_queue_empty(q)) {
#endif
    return q->head->p;
#ifdef _IF_NULL_
    }
    return NULL;
#endif
}

#endif // MSC_QUEUE_H
